/*
 * Funambol is a mobile platform developed by Funambol, Inc. 
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission 
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE 
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Affero General Public License 
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 * 
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite 
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
 * 
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 * 
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably 
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol".
 */

#include "EventSyncSource.h"
#include "spds/SyncStatus.h"
#include "base/Log.h"

EventSyncSource::EventSyncSource(SyncSourceConfig& sc, PIMDataStore& ds, PIMDataConverter& dc, ChangesTracker& ct):
                                eventds((EventDataStore&)ds), eventdc((EventDataConverter&)dc), eventct((EventChangesTracker&)ct), SyncSource(sc.getName(), &sc) {
    ssc = sc;
        
}

EventSyncSource::~EventSyncSource(){
}


/// Used to access configuration of SS
const SyncSourceConfig& EventSyncSource::getConfig() const{ return ssc;}
SyncSourceConfig& EventSyncSource::getConfig(){ return ssc;}

int EventSyncSource::beginSync(){
    LOG.debug("EventSyncSource source: beginSync ");
    int ret = eventds.checkDBFunTable();
    return ret;
}

int EventSyncSource::endSync(){
    LOG.debug("EventSyncSource source: EndSync ");
    eventds.resetFlags(getNextSync()); // @TODO: to be completed
    return 0;
}

void EventSyncSource::setItemStatus(const char* key, int status){
    
}

SyncItem* EventSyncSource::transformIntoSyncItem(const char* identifier, Event& event){
    
    SyncItem* item = NULL;
    if (identifier) {
        item = new SyncItem(identifier);
        const char* data = eventdc.format(event);
        int len = strlen(data);
        item->setData(data, len);
    }
    return item;
}

// --------- Methods to get syncItems from Client --------------
SyncItem* EventSyncSource::getFirstItem() {
    LOG.debug("EventSyncSource source: getFirstItem ");
    eventct.getAll();
    StringBuffer* identifier = eventct.getNextId();
    SyncItem* item = NULL;
    if (identifier && !identifier->empty()) {
        Event* e = (Event*)eventds.getPIMItem(identifier->c_str());
        if (e) {
            item = transformIntoSyncItem(identifier->c_str(), *e);
            delete e;
        }
    }
    return item;
}

SyncItem* EventSyncSource::getNextItem (){
    LOG.debug("EventSyncSource source: getNextItem  ");
    StringBuffer* identifier = eventct.getNextId();
    SyncItem* item = NULL;
    if (identifier && !identifier->empty()) {
        Event* e = (Event*)eventds.getPIMItem(identifier->c_str());
        if (e) {
            item = transformIntoSyncItem(identifier->c_str(), *e);
            delete e;
        }
    }
    return item;    
}

SyncItem* EventSyncSource::getFirstNewItem(){
    LOG.debug("EventSyncSource source: getFirstNewItem ");
    eventct.getModifications(ssc.getLast());
    
    StringBuffer* identifier = eventct.getNextNewId();
    SyncItem* item = NULL;
    if (identifier && !identifier->empty()) {
        Event* e = (Event*)eventds.getPIMItem(identifier->c_str());
        if (e) {
            item = transformIntoSyncItem(identifier->c_str(), *e);
            delete e;
        }
    }
    return item; 
}

SyncItem* EventSyncSource::getNextNewItem (){
    LOG.debug("EventSyncSource source: getNextNewItem");    
    StringBuffer* identifier = eventct.getNextNewId();
    SyncItem* item = NULL;
    if (identifier && !identifier->empty()) {
        Event* e = (Event*)eventds.getPIMItem(identifier->c_str());
        if (e) {
            item = transformIntoSyncItem(identifier->c_str(), *e);
            delete e;
        }
    }
    return item;    
}

SyncItem* EventSyncSource::getFirstUpdatedItem(){
    LOG.debug("EventSync source: getFirstUpdatedItem ");
    StringBuffer* identifier = eventct.getNextUpdateId();
    SyncItem* item = NULL;
    if (identifier && !identifier->empty()) {
        Event* e = (Event*)eventds.getPIMItem(identifier->c_str());
        if (e) {
            item = transformIntoSyncItem(identifier->c_str(), *e);
            delete e;
        }
    }       
    return item;
}

SyncItem* EventSyncSource::getNextUpdatedItem (){
    LOG.debug("EventSync source: getNextUpdatedItem ");
    StringBuffer* identifier = eventct.getNextUpdateId();
    SyncItem* item = NULL;
    if (identifier && !identifier->empty()) {
        Event* e = (Event*)eventds.getPIMItem(identifier->c_str());
        if (e) {
            item = transformIntoSyncItem(identifier->c_str(), *e);
            delete e;
        }
    }       
    return item;   
}

SyncItem* EventSyncSource::getFirstDeletedItem() {
    LOG.debug("EventSync source: getFirstDeletedItem");
    StringBuffer* identifier = eventct.getNextDeleteId();
    SyncItem* item = NULL;
    if (identifier && !identifier->empty()) {        
        item = new SyncItem(identifier->c_str());        
    }       
    return item;          
}

SyncItem* EventSyncSource::getNextDeletedItem (){
    LOG.debug("EventSync source: getNextDeletedItem");
    StringBuffer* identifier = eventct.getNextDeleteId();
    SyncItem* item = NULL;
    if (identifier && !identifier->empty()) {        
        item = new SyncItem(identifier->c_str());        
    }       
    return item;              
}

SyncItem* EventSyncSource::getFirstItemKey(){
    return NULL;
}
SyncItem* EventSyncSource::getNextItemKey(){
    return NULL;
}


// --------- Methods to set syncItems into Client --------------
int EventSyncSource::addItem (SyncItem& item){
    LOG.debug("EventSync source: addItem");
    StringBuffer identifier;
    int ret = STC_COMMAND_FAILED;
    PIMItem* pimItem = eventdc.parse((const char*)item.getData());
    
    if (pimItem == NULL) {
        LOG.error("Error parsing the item to insert: &s", (const char*)item.getData());
        return ret;
    }    
    if (eventds.addPIMItem(identifier, *pimItem) == 0) {        
        item.setKey(identifier.c_str());
        ret = STC_ITEM_ADDED;
        LOG.debug("Added item %s", identifier.c_str());
    } else {
        LOG.error("Add item %s error", (const char*)item.getData());
    }
    return ret;
}

int EventSyncSource::updateItem(SyncItem& item){
    LOG.debug("EventSync source: updateItem");
    int ret = STC_COMMAND_FAILED;
    
    PIMItem* pimItem = eventdc.parse((const char*)item.getData());
    
    if (pimItem == NULL) {
        LOG.error("Error parsing the item to update: &s", (const char*)item.getData());
        return ret;
    }    
    if (eventds.updatePIMItem(item.getKey(), *pimItem) == 0) {
        ret = STC_OK;
        LOG.debug("Updated item %s", item.getKey());	    
    } else {
        LOG.error("Updated item %s error", item.getKey());
    }
    return ret;
}

int EventSyncSource::deleteItem(SyncItem& item) {
    LOG.debug("EventSync source: deleteItem");
    int ret = STC_COMMAND_FAILED;
    
    if (eventds.deletePIMItem(item.getKey()) == 0) {
        ret = STC_OK;
        LOG.debug("Deleted item %s", item.getKey());
    } else {
        LOG.error("Deleted item %s error", item.getKey());
    }
    return ret;

}

int EventSyncSource::removeAllItems() {

    int ret = eventds.removeAllItems();
    
    setLastAnchor("");
    ssc.setLast(0);
    
    return ret;
}


